package eco.footprint;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.TreeMap;

import android.content.res.XmlResourceParser;

public class FootprintUtil {
	Question[] mQuestions;
	Category[] mCategories;
	Tip[] mTips;
	double globalHectareConstant = 2.1;
	boolean calculateScenarioQuestions = false;

	// String CATEGORY_FOOD = "1";
	// String CATEGORY_SHELTER = "2";
	// String CATEGORY_ELECTRICITY = "2.5";
	// String CATEGORY_MOBILITY = "3";
	// String CATEGORY_GOODS = "4";
	// String CATEGORY_SERVICES = "5";
	// String CATEGORY_GOVERNANCE = "6";
	//
	// int QUIZ_POSITION_DIET = 1;
	// int QUIZ_POSITION_LOCAL_FOOD = 2;
	// int QUIZ_POSITION_GOODS = 3;
	// int QUIZ_POSITION_SHELTER = 4;
	// int QUIZ_POSITION_ELECTRICITY = 5;
	// int QUIZ_POSITION_MOBILITY = 6;
	// int QUIZ_POSITION_PUBLIC_TRANSIT = 7;
	// int QUIZ_POSITION_AIRPLANE = 8;
	// int QUIZ_POSITION_END = 9;
	//
	// int[] questionsBasicArray = new int[] { 1, 5, 10, 19, 20, 21, 22, 23, 24,
	// 25, 26, 33, 34, 35, 36, 37, 38, 39, 42 };
	// int[] questionsDetailedArray = new int[] { 2, 3, 4, 6, 7, 8, 9, 11, 12,
	// 13,
	// 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31,
	// 32, 33, 34, 35, 36, 37, 38, 40, 41, 42 };
	// int[] questionsFullArray = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
	// 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
	// 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42 };

	public void initQuestions(XmlResourceParser xrp) {
		ArrayList<Question> questions = new ArrayList<Question>();
		try {
			int questionID = 0;
			int questionType = 0;
			String questionMinText = null;
			String questionMaxText = null;
			String questionText = null;
			ArrayList<Answer> answers = new ArrayList<Answer>();
			int answerID = 0;
			String answerText = null;
			ArrayList<Value> answerValues = new ArrayList<Value>();

			while (xrp.getEventType() != XmlResourceParser.END_DOCUMENT) {
				if (xrp.getEventType() == XmlResourceParser.START_TAG) {
					String s = xrp.getName();
					if (s.equals("question_answer_set")) {
						String inputType = xrp.getAttributeValue(null,
								"inputType");

						if (inputType.equalsIgnoreCase("radioButton")) {
							questionType = Question.TYPE_RADIOBUTTON;
						} else if (inputType.equalsIgnoreCase("slider")) {
							questionType = Question.TYPE_SLIDER;
						}

						questionID = xrp.getAttributeIntValue(null, "q_id", 0);
						questionMinText = xrp.getAttributeValue(null,
								"left_text");
						questionMaxText = xrp.getAttributeValue(null,
								"right_text");
						questionText = xrp.getAttributeValue(null, "q_str");
						answers = new ArrayList<Answer>();

					} else if (s.equals("answer")) {

						String answerIDStr = xrp.getAttributeValue(null,
								"ans_id");

						String[] parts = answerIDStr.split("\\.");
						if (parts != null && parts.length > 1) {
							answerID = Integer.parseInt(parts[1]);
						}

						answerText = xrp.getAttributeValue(null, "ans_str");

						answerValues = new ArrayList<Value>();

					} else if (s.equals("value")) {
						Value value = new Value();
						value.mBuiltArea = xrp.getAttributeFloatValue(null,
								"built", 0.0f);
						value.mCatID = xrp.getAttributeValue(null, "cat_id");
						value.mCropLand = xrp.getAttributeFloatValue(null,
								"crop", 0.0f);
						value.mEnergyLand = xrp.getAttributeFloatValue(null,
								"energy", 0.0f);
						value.mFishingGrounds = xrp.getAttributeFloatValue(
								null, "fish", 0.0f);
						value.mForest = xrp.getAttributeFloatValue(null,
								"forest", 0.0f);
						value.mPasture = xrp.getAttributeFloatValue(null,
								"graz", 0.0f);

						String val = xrp.getAttributeValue(null, "value");
						if (val != null && val.trim().length() > 0)
							value.mValue = Float.parseFloat(val);

						answerValues.add(value);
					}
				} else if (xrp.getEventType() == XmlResourceParser.END_TAG) {
					String s = xrp.getName();
					if (s.equals("question_answer_set")) {
						Question question = new Question();
						question.mID = questionID;
						question.mType = questionType;
						question.mMinText = questionMinText;
						question.mMaxText = questionMaxText;
						question.mQuestion = questionText;
						question.mAnswers = new Answer[answers.size()];
						question.mAnswers = answers.toArray(question.mAnswers);

						questions.add(question);
					} else if (s.equals("answer")) {
						Answer answer = new Answer();
						answer.mID = answerID;
						answer.mAnswer = answerText;
						answer.mValues = new Value[answerValues.size()];
						answer.mValues = answerValues.toArray(answer.mValues);
						answers.add(answer);
					}
				}
				xrp.next();
			}
			xrp.close();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		mQuestions = new Question[questions.size()];
		mQuestions = questions.toArray(mQuestions);
	}

	public void initCategories(XmlResourceParser xrp) {
		ArrayList<Category> categories = new ArrayList<Category>();
		try {
			String categoryID = "";
			String text = "";
			float energyLand = 0.0f;
			float cropLand = 0.0f;
			float pasture = 0.0f;
			float forest = 0.0f;
			float builtArea = 0.0f;
			float fishingGrounds = 0.0f;
			String tag = "";
			while (xrp.getEventType() != XmlResourceParser.END_DOCUMENT) {
				if (xrp.getEventType() == XmlResourceParser.START_TAG) {
					String s = xrp.getName();
					if (s.equals("item")) {
						categoryID = xrp.getAttributeValue(null, "cat_id");
					} else
						tag = s;
				} else if (xrp.getEventType() == XmlResourceParser.END_TAG) {
					String s = xrp.getName();
					if (s.equals("item")) {
						Category c = new Category();
						c.mBuiltArea = builtArea;
						c.mCategoryID = categoryID;
						c.mCropLand = cropLand;
						c.mEnergyLand = energyLand;
						c.mFishingGrounds = fishingGrounds;
						c.mForest = forest;
						c.mPasture = pasture;
						categories.add(c);
					}
				} else if (xrp.getEventType() == XmlResourceParser.TEXT) {
					text = xrp.getText().trim();
					if (text.length() > 1)
						if (tag.equals("energy_land")) {
							energyLand = Float.parseFloat(text);
						} else if (tag.equals("crop_land")) {
							cropLand = Float.parseFloat(text);
						} else if (tag.equals("pasture")) {
							pasture = Float.parseFloat(text);
						} else if (tag.equals("forest")) {
							forest = Float.parseFloat(text);
						} else if (tag.equals("built_area")) {
							builtArea = Float.parseFloat(text);
						} else if (tag.equals("fishing_grounds")) {
							fishingGrounds = Float.parseFloat(text);
						}
				}
				xrp.next();
			}
			xrp.close();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		mCategories = new Category[categories.size()];
		mCategories = categories.toArray(mCategories);
	}

	static int[] insertElement(int original[], int element) {
		int length = original.length;
		int destination[] = new int[length + 1];
		System.arraycopy(original, 0, destination, 0, length);
		destination[length] = element;
		return destination;
	}

	public void initTips(XmlResourceParser xrp) {
		ArrayList<Tip> tips = new ArrayList<Tip>();
		try {
			int tipID = 0;
			int[] questionIDs = new int[] {};
			String tipText = null;
			while (xrp.getEventType() != XmlResourceParser.END_DOCUMENT) {
				if (xrp.getEventType() == XmlResourceParser.START_TAG) {
					String s = xrp.getName();
					if (s.equals("item")) {
						tipID = xrp.getAttributeIntValue(null, "id", 0);
						String iDs = xrp.getAttributeValue(null, "q_ids");
						String[] iDsArray = iDs.split(",");
						for (String id : iDsArray) {
							id = id.trim();
							if (!id.equalsIgnoreCase("")) {
								questionIDs = insertElement(questionIDs,
										Integer.parseInt(id));
							}
						}
						tipText = xrp.getAttributeValue(null, "desc");
					}
				} else if (xrp.getEventType() == XmlResourceParser.END_TAG) {
					String s = xrp.getName();
					if (s.equals("item")) {
						Tip tip = new Tip(tipID, questionIDs, tipText);
						tips.add(tip);
					}
				}
				xrp.next();
			}
			xrp.close();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		mTips = new Tip[tips.size()];
		mTips = tips.toArray(mTips);
	}

	class ValueComparator implements Comparator {
		Map base;

		public ValueComparator(Map base) {
			this.base = base;
		}

		public int compare(Object a, Object b) {

			if ((Double) base.get(a) < (Double) base.get(b)) {
				return 1;
			} else if ((Double) base.get(a) == (Double) base.get(b)) {
				return 0;
			} else {
				return -1;
			}
		}
	}

	public int[] sortQuestionsByInfluence(int[] answers) {
		int[] result = new int[] {};
		int questionLen = mQuestions.length;
		Hashtable<String, Category> categoriesCopy = new Hashtable<String, Category>();
		for (int i = 0; i < mCategories.length; i++) {
			categoriesCopy.put(mCategories[i].mCategoryID, mCategories[i]
					.clone());
		}
		HashMap<Integer, Double> map = new HashMap<Integer, Double>();
		ValueComparator bvc = new ValueComparator(map);
		TreeMap<Integer, Double> sorted_map = new TreeMap(bvc);
		Question question = null;
		Answer answer = null;
		for (int i = 0; i < questionLen; i++) {
			double val = 0.0;
			int answerIndex = answers[i];
			if (answers[i] != -1) {
				question = mQuestions[i];
				answer = mQuestions[i].mAnswers[answerIndex];
				for (int j = 0; j < answer.mValues.length; j++) {
					Value value = answer.mValues[j];
					String vCatID = value.mCatID;
					Category cat = categoriesCopy.get(vCatID);
					if (cat != null) {
						val += cat.mBuiltArea * value.mBuiltArea
								+ cat.mCropLand * value.mCropLand
								+ cat.mEnergyLand * value.mEnergyLand
								+ cat.mFishingGrounds * value.mFishingGrounds
								+ cat.mForest * value.mForest + cat.mPasture
								* value.mPasture;
					}
				}
				map.put(i, val);
			}
		}
		sorted_map.putAll(map);
		for (Integer key : sorted_map.keySet()) {
			result = insertElement(result, key.intValue());
		}
		return result;
	}

	public String[] getTipsByQuestions(int[] questions) {
		String[] result = new String[] {};
		int[] ids = new int[] {};
		// Arrays.sort(questions);
		for (int j = 0; j < questions.length; j++) {
			for (int i = 0; i < mTips.length; i++) {
				boolean tip = false;
				boolean add = true;
				for (int k = 0; k < mTips[i].mQuestionIDs.length; k++) {
					if (mTips[i].mQuestionIDs[k] == questions[j] + 1) {
						tip = true;
						break;
					}
				}
				for (int l = 0; l < ids.length; l++) {
					if (ids[l] == i) {
						add = false;
						break;
					}
				}

				if (tip && add) {

					ids = insertElement(ids, i);
					// Arrays.sort(ids);

				}
			}
		}
		result = new String[ids.length];
		for (int i = 0; i < ids.length; i++) {
			result[i] = mTips[ids[i]].mText;
		}
		return result;
	}

	public FootprintResult calculateFootprintFromAnswers(int[] answers) {
		int questionLen = mQuestions.length;

		Hashtable<String, Category> categoriesCopy = new Hashtable<String, Category>();
		for (int i = 0; i < mCategories.length; i++) {
			categoriesCopy.put(mCategories[i].mCategoryID, mCategories[i]
					.clone());
		}

		Question question = null;
		Answer answer = null;

		for (int i = 0; i < questionLen; i++) {
			int answerIndex = answers[i];
			if (answers[i] != -1) {
				question = mQuestions[i];
				answer = mQuestions[i].mAnswers[answerIndex];

				for (int j = 0; j < answer.mValues.length; j++) {
					Value value = answer.mValues[j];
					String vCatID = value.mCatID;

					Category cat = categoriesCopy.get(vCatID);
					if (cat != null) {
						cat = adjustScore(question, value, cat);
					}
				}
			}
		}
		FootprintResult result = compileCategories(categoriesCopy.values());
		return result;
	}

	public Category adjustScore(Question question, Value value,
			Category category) {
		Category result = category;
		if (value.mValue > 0) {
			double natCoeff = value.mValue / question.mNationalAverage;
			result.mCropLand = category.mCropLand * natCoeff;
			result.mBuiltArea = category.mBuiltArea * natCoeff;
			result.mPasture = category.mPasture * natCoeff;
			result.mFishingGrounds = category.mFishingGrounds * natCoeff;
			result.mEnergyLand = category.mEnergyLand * natCoeff;
			result.mForest = category.mForest * natCoeff;
		} else {
			result.mCropLand = category.mCropLand * value.mCropLand;
			result.mBuiltArea = category.mBuiltArea * value.mBuiltArea;
			result.mPasture = category.mPasture * value.mPasture;
			result.mFishingGrounds = category.mFishingGrounds
					* value.mFishingGrounds;
			result.mEnergyLand = category.mEnergyLand * value.mEnergyLand;
			result.mForest = category.mForest * value.mForest;
		}
		return result;
	}

	public FootprintResult compileCategories(Iterable<Category> categories) {
		FootprintResult result = new FootprintResult();
		for (Category cat : categories) {

			double catTotal = cat.mEnergyLand + cat.mCropLand + cat.mPasture
					+ cat.mForest + cat.mBuiltArea + cat.mFishingGrounds;
			result.energyTotal = result.energyTotal + cat.mEnergyLand;
			result.cropTotal = result.cropTotal + cat.mCropLand;
			result.grazTotal = result.grazTotal + cat.mPasture;
			result.forestTotal = result.forestTotal + cat.mForest;
			result.builtTotal = result.builtTotal + cat.mBuiltArea;
			result.fishTotal = result.fishTotal + cat.mFishingGrounds;

			int mainCatID = Integer.parseInt(cat.mCategoryID.substring(0, 1));
			switch (mainCatID) {
			case 1: {
				result.foodTotal = result.foodTotal + catTotal;
				break;
			}
			case 2: {
				result.shelterTotal = result.shelterTotal + catTotal;
				break;
			}
			case 3: {
				result.mobilityTotal = result.mobilityTotal + catTotal;
				break;
			}
			case 4: {
				result.goodsTotal = result.goodsTotal + catTotal;
				break;
			}
			case 5: {
				result.servicesTotal = result.servicesTotal + catTotal;
				break;
			}
			case 6: {
				result.governanceTotal = result.governanceTotal + catTotal;
				break;
			}
			default: {
				break;
			}
			}
		}

		result.numberOfEarths = result.totalScore() / globalHectareConstant;
		return result;
	}
}
